package com.atguigu.gulimall.product.service.impl;

import com.atguigu.common.constant.ProductConstant;
import com.atguigu.gulimall.product.dao.AttrAttrgroupRelationDao;
import com.atguigu.gulimall.product.dao.AttrDao;
import com.atguigu.gulimall.product.entity.AttrAttrgroupRelationEntity;
import com.atguigu.gulimall.product.entity.AttrEntity;
import com.atguigu.gulimall.product.service.AttrService;
import com.atguigu.gulimall.product.vo.AttrGoupRelationVo;
import com.atguigu.gulimall.product.vo.AttrGroupWithAttrResVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.product.dao.AttrGroupDao;
import com.atguigu.gulimall.product.entity.AttrGroupEntity;
import com.atguigu.gulimall.product.service.AttrGroupService;


@Service("attrGroupService")
public class AttrGroupServiceImpl extends ServiceImpl<AttrGroupDao, AttrGroupEntity> implements AttrGroupService {
    @Autowired
    private AttrAttrgroupRelationDao relationDao;
    @Autowired
    private AttrDao attrDao;
    @Autowired
    private AttrGroupDao groupDao;

    @Autowired
    private AttrService attrService;
    /**
     * v1拿到该分类下的所有分组，并且分组里面还关联了属性
     * @param catelogId
     * @return
     */
    @Override
    public List<AttrGroupWithAttrResVo> queryAttrAndGroupByCategoryIdV1(Long catelogId){
        //如果说该分类下没有分组 groupList长度为0
        List<AttrGroupEntity> groupList = baseMapper.selectList(new LambdaQueryWrapper<AttrGroupEntity>()
                .eq(AttrGroupEntity::getCatelogId, catelogId));
        if (groupList != null && groupList.size()>0){
            //这样才能保证group不为空
            List<AttrGroupWithAttrResVo> groupWithAttrResVos = groupList.stream().map((group) -> {
                List<AttrEntity> attrList = attrService.getRelationAttrByGroupId(group.getAttrGroupId());
                AttrGroupWithAttrResVo attrGroupWithAttrResVo = new AttrGroupWithAttrResVo();
                BeanUtils.copyProperties(group, attrGroupWithAttrResVo);
                attrGroupWithAttrResVo.setAttrs(attrList);
                return attrGroupWithAttrResVo;
            }).collect(Collectors.toList());
            return groupWithAttrResVos;
        }
       return null;
    }
    /**
     * 拿到该分类下的所有分组，并且分组里面还关联了属性
     * @param catelogId
     * @return
     */
    @Override
    public List<AttrGroupWithAttrResVo> queryAttrAndGroupByCategoryId(Long catelogId) {
        List<AttrGroupEntity> groupList = baseMapper.selectList(new LambdaQueryWrapper<AttrGroupEntity>()
                .eq(AttrGroupEntity::getCatelogId, catelogId));
        if (groupList !=null && groupList.size()>0){
            //你有可能分类下面没有分组,有分组才查出分组
            List<Long> gids = groupList.stream().map((item) -> {
                return item.getAttrGroupId();
            }).collect(Collectors.toList());
            //根据gid，到属性分组关联表里面拿到这些分组下的所有属性
            List<AttrAttrgroupRelationEntity> relationList = relationDao.selectList(new LambdaQueryWrapper<AttrAttrgroupRelationEntity>()
                    .in(AttrAttrgroupRelationEntity::getAttrGroupId, gids));
            List<AttrGroupWithAttrResVo> attrGroupWithAttrResVoList = new ArrayList<>();
            for (AttrGroupEntity attrGroupEntity : groupList) {
                List<Long> attrIdsOfCurrentGroup = relationList.stream().filter((relation) -> {
                    return relation.getAttrGroupId() == attrGroupEntity.getAttrGroupId();
                }).map((relation) -> {
                    return relation.getAttrId();
                }).collect(Collectors.toList());
                if (attrIdsOfCurrentGroup !=null && attrIdsOfCurrentGroup.size()>0){
                    //代表该分组下已经关联了属性
                    List<AttrEntity> attrList = attrDao.selectList(new LambdaQueryWrapper<AttrEntity>()
                            .in(AttrEntity::getAttrId, attrIdsOfCurrentGroup));
                    AttrGroupWithAttrResVo attrGroupWithAttrResVo = new AttrGroupWithAttrResVo();
                    BeanUtils.copyProperties(attrGroupEntity, attrGroupWithAttrResVo);
                    attrGroupWithAttrResVo.setAttrs(attrList);
                    attrGroupWithAttrResVoList.add(attrGroupWithAttrResVo);
                }else {
                    //走这里代表该分组下还没关联属性
                    return null;
                }
            }
            return attrGroupWithAttrResVoList;
        }else {
            //走这里证明该分类下没有分组
            return null;
        }
    }
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrGroupEntity> page = this.page(
                //下面这句是默认调用了无参构造方法，所以不奇怪。后面的getPage方法就返回了一个Page<T>page 对象
                new Query<AttrGroupEntity>().getPage(params),
                new QueryWrapper<AttrGroupEntity>()
        );
        //PageUtils其实就是把page里面的东西取出来又封装到自己的结构体中
        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageByCatId(Map<String, Object> params, Long catId) {
        //前端规定没点三级分类就传0，也就是查所有分组
        if (catId == 0) {
            return this.queryPage(params);
        } else {
            //Query是你自己封装的
            Query<AttrGroupEntity> query = new Query<>();
            //就是把map中接收到前端的分页数据封装到ipage里面
            IPage<AttrGroupEntity> ipage = query.getPage(params);
            //造一个AttrGroupEntity对应表的QueryWrapper
            QueryWrapper<AttrGroupEntity> queryWrapper = new QueryWrapper<>();
            //SELECT attr_group_id,icon,catelog_id,sort,descript,attr_group_name FROM pms_attr_group
            // WHERE (catelog_id = ? AND ( (attr_group_id = ? OR attr_group_name LIKE ?) ))
            queryWrapper.eq("catelog_id",catId);
            String key=(String) params.get("key");
            //long lkey = Long.parseLong(key);
            if (StringUtils.isNotEmpty(key)){
//                queryWrapper.eq("attr_group_id",key).or().like("attr_group_name",key);
                //雷神的写法
                queryWrapper.and(
                        //下面这句话，就相当于有个匿名类A继承了 Consumer接口，并实现了accept方法（方法体也就是lambda表达式逻辑部分），
                        // 并new了A类对象a
                        // 这个对象a被传递给default Children and(Consumer<Param> consumer)
                        //consumer就是a
                        //最终会执行consumer.accept方法，obj是参数，对与obj来说，执行{}内的操作。
                        //1.在内存造了一个实现了Consumer接口的匿名内部类
                        //2.在匿名内部类中实现了accept方法，obj是该方法的参数，这里在上下文中就代表queryWrapper
                        //同时方法的方法体部分就是 obj.eq("attr_group_id",key).or().like("attr_group_name",key);
                        //3.返回该匿名内部类的一个对象a,其实整个lambda表达式就代表这个对象a
                        //4.最终在层层调用中会调用a.accept方法执行其中的逻辑。
                        (obj)->{
                    obj.eq("attr_group_id",key).or().like("attr_group_name",key);
                });
            }
            IPage<AttrGroupEntity> page = this.page(ipage,queryWrapper);
            return new PageUtils(page);
        }
    }

    @Override
    public PageUtils queryPageByCatIdv1(Map<String, Object> params, Long catId) {
        //不管分类id是不是0，我都需要有搜索的功能，要搜索，一个是根据组id搜 或者 通过组名模糊查询
        QueryWrapper<AttrGroupEntity> queryWrapper = new QueryWrapper<>();
        String key=(String) params.get("key");
        if (StringUtils.isNotEmpty(key)){
            queryWrapper.eq("attr_group_id",key).or().like("attr_group_name",key);
        }
        //意思就是说不具体查某个分类的分组，而是查所有分组，不过是进行分页和条件查询
        if (catId ==0){
            //Query是你自己封装的
            Query<AttrGroupEntity> query = new Query<>();
            //就是把map中接收到前端的分页数据封装到ipage里面
            IPage<AttrGroupEntity> ipage = query.getPage(params);
            IPage<AttrGroupEntity> page = this.page(ipage,queryWrapper);
            return new PageUtils(page);
        }else {
            //走这里的代码就证明，前端请求了具体分类下的分组
            queryWrapper.and((obj)->{
                obj.eq("catelog_id",catId);
            });
            Query<AttrGroupEntity> query = new Query<>();
            //就是把map中接收到前端的分页数据封装到ipage里面
            IPage<AttrGroupEntity> ipage = query.getPage(params);
            IPage<AttrGroupEntity> page = this.page(ipage,queryWrapper);

            return new PageUtils(page);
        }
    }

    /**
     * 根据分组id查出该分组下的所有基本属性
     * @param attrgropId
     * @return
     */
    @Override
    public List<AttrEntity> listAttrByGroupId(Long attrgropId) {
        LambdaQueryWrapper<AttrAttrgroupRelationEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttrAttrgroupRelationEntity::getAttrGroupId,attrgropId);
        List<AttrAttrgroupRelationEntity> list = relationDao.selectList(wrapper);
        if (list.size()>0 && list !=null){
            List<Long> attrIdsList = list.stream().map((obj) -> {
                return obj.getAttrId();
            }).collect(Collectors.toList());
            List<AttrEntity> attrEntityList = attrDao.selectBatchIds(attrIdsList);
            return attrEntityList;
        }
        return null;
    }

    /**
     * 该版本在循环里操作数据库，不建议这么做，而是一条语句解决问题，看V1版本
     * @param relationVos
     */
    @Override
    public void removeByAttrIdAndGroupId(List<AttrGoupRelationVo> relationVos) {
        for (AttrGoupRelationVo relationVo : relationVos) {
            LambdaQueryWrapper<AttrAttrgroupRelationEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AttrAttrgroupRelationEntity::getAttrId,relationVo.getAttrId())
                    .eq(AttrAttrgroupRelationEntity::getAttrGroupId,relationVo.getAttrGroupId());
            relationDao.delete(wrapper);
        }
    }

    @Override
    public void removeByAttrIdAndGroupIdV1(List<AttrGoupRelationVo> relationVos) {
        List<AttrAttrgroupRelationEntity> collect = relationVos.stream().map((item) -> {
            AttrAttrgroupRelationEntity attrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            attrgroupRelationEntity.setAttrId(item.getAttrId());
            attrgroupRelationEntity.setAttrGroupId(item.getAttrGroupId());
            return attrgroupRelationEntity;
        }).collect(Collectors.toList());
        relationDao.removeByAttrIdAndGroupId(collect);
    }

    /**
     *
     * @param params
     * @param attrgroupId
     * @return
     */
    @Override
    public PageUtils queryNoRelationsOfThisGroup(Map<String, Object> params, Long attrgroupId) {
        //首先第一条，你关联只能关联分组所属分类下的基本属性,销售属性没有属于的分组，也就是规定不能分到某个组里去。
        AttrGroupEntity group = baseMapper.selectById(attrgroupId);
        Long catelogId = group.getCatelogId();
        LambdaQueryWrapper<AttrEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttrEntity::getCatelogId,catelogId).eq(AttrEntity::getAttrType,ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode());
        String key = (String) params.get("key");
        if (StringUtils.isNotEmpty(key)){
            wrapper.like(AttrEntity::getAttrName,key);
        }
        //下面这个List就包含了该分组所属分类下的所有基本属性
        List<AttrEntity> attrList = attrDao.selectList(wrapper);
        //拿到该分类下的所有分组
        LambdaQueryWrapper<AttrGroupEntity> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(AttrGroupEntity::getCatelogId,catelogId);
        List<AttrGroupEntity> groupList = groupDao.selectList(wrapper1);
        //该分类下属分组的id集合
        List<Long> groupIds = groupList.stream().map((item) -> {
            return item.getAttrGroupId();
        }).collect(Collectors.toList());
        //拿到该分类所有分组下所有已经关联了的基本属性(该分类本分组已关联的基本属性，和该分类下其他分组已关联的基本属性）
        List<AttrEntity>attrBaseOutOf=attrDao.selectGroupListOfAttrBase(groupIds);
        //用该分类下的所有基本属性挖掉该分类下所有分组已经关联的基本属性，这就剩下了该分类下还没关联的基本属性
        attrList.removeAll(attrBaseOutOf);
        String order=(String)params.get("order");
        if (StringUtils.isNotEmpty(order)){
            if ("asc".equalsIgnoreCase(order)){
                Collections.sort(attrList, Comparator.comparingLong(AttrEntity::getAttrId));
            }
            if ("desc".equalsIgnoreCase(order)){
                Collections.sort(attrList, Comparator.comparingLong(AttrEntity::getAttrId).reversed());
            }
        }
        int page = Integer.parseInt((String) params.get("page"));
        int limit = Integer.parseInt((String) params.get("limit"));
        int startIndex = (page - 1) * limit;
        int endIndex = Math.min(startIndex + limit, attrList.size());
        List<AttrEntity> end = attrList.subList(startIndex, endIndex);
        return new PageUtils(end,end.size(),limit,page);
    }

    @Override
    public PageUtils queryNoRelationsOfThisGroupV1(Map<String, Object> params, Long attrgroupId) {
        AttrGroupEntity group = groupDao.selectById(attrgroupId);
        Long catelogId = group.getCatelogId();
        //拿到当前分类下的所有基本属性，注意销售属性是不会被划入某个组的，属性分组表里，也是基本属性和分组的关联
//        List<AttrEntity> attrbaseList = attrDao.selectList(new LambdaQueryWrapper<AttrEntity>().eq(AttrEntity::getCatelogId, catelogId)
//                .eq(AttrEntity::getAttrType, ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()));
//        //拿到该分类下所有基本属性的ids
//        List<Long> attrbaseIds = attrbaseList.stream().map((item) -> {
//            return item.getAttrId();
//        }).collect(Collectors.toList());
        //拿到当前分类下的所有分组的id集合
        List<AttrGroupEntity> groupList = groupDao.selectList(new LambdaQueryWrapper<AttrGroupEntity>()
                .eq(AttrGroupEntity::getCatelogId, catelogId));
        List<Long> gids = groupList.stream().map((item) -> {
            return item.getAttrGroupId();
        }).collect(Collectors.toList());
        //在关联表中拿到该分类下所有分组已关联的基本属性，你要注意这种写法
        //如果该分类下的所有分组你都没关联属性，那么这个relationList的长度为0
        List<AttrAttrgroupRelationEntity> relationList = relationDao.selectList(new LambdaQueryWrapper<AttrAttrgroupRelationEntity>()
                .in(AttrAttrgroupRelationEntity::getAttrGroupId, gids));
        //在联表中拿到该分类下所有分组已关联的基本属性id集合
        //那么这个relationList的长度为0的前提下attrbaseIds的长度也为0
        List<Long> attrbaseIds = relationList.stream().map((item) -> {
            return item.getAttrId();
        }).collect(Collectors.toList());
        //在上面注释的代码中，我的想法是拿到该分类下的所有基本属性后，再排查该分类下所有分组在关联表中的基本属性
        //现在的思路是，我直接拿到关联表中该分类所有分组已关联的基本属性的id集合，直接到属性表里去查，这个id集合作为一个判断条件
        //attrbaseIds的长度为0的前提下.notIn(AttrEntity::getAttrId, attrbaseIds);不会成里，也就是notIn里面没传入东西，所以要报错
        LambdaQueryWrapper<AttrEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttrEntity::getCatelogId, catelogId).eq(AttrEntity::getAttrType, ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode());
        //你思路就是：送回前端的未分配的基本属性=该分类下的所有属性-该分类下的所有分组已经关联了的基本属性
        //当然如果该分类下的分组都没关联 你当然就需要有 排除 该分类下的所有分组已经关联了的基本属性 的做法
        if (attrbaseIds!=null && attrbaseIds.size()>0){
            //走这里表示，该分类下有分组关联了基本属性，这里你需要排查这些被关联过的基本属性
            wrapper.notIn(AttrEntity::getAttrId, attrbaseIds);
        }
        String key = (String) params.get("key");
        if (StringUtils.isNotEmpty(key)){
            wrapper.and((obj)->{
                obj.like(AttrEntity::getAttrName,key).or().like(AttrEntity::getAttrId,key);
            });
        }
        String order = (String) params.get("order");
        if (StringUtils.isNotEmpty(order)){
            if ("asc".equalsIgnoreCase(order)){
                wrapper.orderByAsc(AttrEntity::getAttrId);
            }
            if ("desc".equalsIgnoreCase(order)){
                wrapper.orderByDesc(AttrEntity::getAttrId);
            }
        }
        Query<AttrEntity> query = new Query<>();
        //主要就是把分页的limit和size封装到page里面
        IPage<AttrEntity> page = query.getPage(params);
        IPage<AttrEntity> iPage = attrDao.selectPage(page, wrapper);
        return new PageUtils(iPage);
    }

    @Override
    public void saveAttrGroupRelation(List<AttrGoupRelationVo> relationVos) {
        List<AttrAttrgroupRelationEntity> relationList = relationVos.stream().map((item) -> {
            AttrAttrgroupRelationEntity relation = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(item, relation);
            return relation;
        }).collect(Collectors.toList());
        relationDao.insertBatch(relationList);
    }

}